package com.weimob.mcloud.wechatwork.customer.job;

import com.alibaba.fastjson.JSON;
import com.weimob.dq.client.api.DqFramework;
import com.weimob.mcloud.wechatwork.common.utils.JsonUtil;
import com.weimob.mcloud.wechatwork.core.base.MultiResponse;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.config.clue.ClueCfg;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.CustomerStageRelation;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.CustomerStageRemindRecord;
import com.weimob.mcloud.wechatwork.core.enums.clue.PotentialSettingEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerStageRelationService;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerStageRemindRecordService;
import com.weimob.mcloud.wechatwork.core.service.customer.request.QueryListRemindRecordRequest;
import com.weimob.mcloud.wechatwork.customer.config.DqConfig;
import com.weimob.mcloud.wechatwork.customer.listener.event.CustomerStageRemindEvent;
import com.weimob.soa.common.response.SoaResponse;
import com.weimob.soa.common.utils.SoaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author jiawei.you01
 * @date 2022/9/21 17:45
 * @since 1.0
 */
@Slf4j
public class RemindEmployeeFollowUpThread implements Runnable {

    PrivateSphere privateSphere;

    CustomerStageRelationService customerStageRelationService;

    private String stageId;

    private List<ClueCfg> clueCfgs;

    CustomerStageRemindRecordService remindRecordService;

    private DqFramework dqClient;

    private Boolean openDelay;

    int pageSize = 200;


    public RemindEmployeeFollowUpThread(PrivateSphere privateSphere
            , CustomerStageRelationService customerStageRelationService
            , String stageId, List<ClueCfg> clueCfgs
            , CustomerStageRemindRecordService remindRecordService
            , DqFramework dqClient
            , Boolean openDelay) {
        this.privateSphere = privateSphere;
        this.customerStageRelationService = customerStageRelationService;
        this.stageId = stageId;
        this.clueCfgs = clueCfgs;
        this.remindRecordService = remindRecordService;
        this.dqClient = dqClient;
        this.openDelay = openDelay;
    }


    @Override
    public void run() {
        int pageNum = 1;
        List<CustomerStageRelation> dataList = new ArrayList<>();

        /**
         * 已经发送过延迟消息的key : stageId:employeeId
         */
        List<String> sendKey = new ArrayList<>();
        do {
            try {
                ClueCfg followClueCfg = clueCfgs.stream().filter(i ->
                        PotentialSettingEnum.CUSTOMER_PROCESS_FOLLOW.equals(i.getPotentialSettingEnum())).findAny().orElse(null);
                if (followClueCfg == null || Boolean.FALSE.equals(followClueCfg.getRuleOpenFlag())) {
                    //如果客户没有打开跟进提醒，则直接返回
                    log.info("当前客户阶段跟进提醒没有打开,stageId:{},followClueCfg:{}", stageId, JsonUtil.obj2Str(followClueCfg));
                    return;
                }
                if (StringUtils.isBlank(followClueCfg.getRuleValue())) {
                    log.warn("remindJob.ruleValue is null,id:{}", followClueCfg.getId());
                    return;
                }


                log.info("查询客户阶段关系表,stageId:{},pageNum:{}", stageId, pageNum);
                SingleRequest<CustomerStageRelation> singleRequest = buildFetchRelationListRequest(pageNum);
                SoaResponse<MultiResponse<CustomerStageRelation>, ?> multiResponseSoaResponse = customerStageRelationService.fetchRelationList(singleRequest);
                MultiResponse<CustomerStageRelation> unpack = SoaUtil.unpack(multiResponseSoaResponse);
                dataList = unpack.getDataList();
                if(CollectionUtils.isEmpty(dataList)){
                    break;
                }

                //过滤出remark为空的数据且不是终态的数据
                dataList = dataList.stream().filter(i-> StringUtils.isEmpty(i.getRemark()) && !i.getHasEnd()).collect(Collectors.toList());
                if(CollectionUtils.isEmpty(dataList)){
                    pageNum++;
                    continue;
                }
                List<String> employeeIdList = dataList.stream().map(CustomerStageRelation::getEmployeeId).distinct().collect(Collectors.toList());

                //查询最新的一次发送提醒时间
                QueryListRemindRecordRequest request = new QueryListRemindRecordRequest();
                request.setStageId(stageId);
                request.setEmployeeIdList(employeeIdList);
                SoaResponse<MultiResponse<CustomerStageRemindRecord>, Void> multiResponseVoidSoaResponse = remindRecordService.queryList(request);
                List<CustomerStageRemindRecord> remindRecordList = SoaUtil.unpack(multiResponseVoidSoaResponse).getDataList();

                Map<String, CustomerStageRemindRecord> employeeIdRemindRecordMap = remindRecordList
                        .stream()
                        .collect(Collectors.toMap(CustomerStageRemindRecord::getEmployeeId, i -> i, (t1, t2) -> t1));

                //计算超过多少时间发送提醒  毫秒
                long followClueTime = calculateClueCfgTime(followClueCfg);
                Long delayTime = calculateDelayTime(followClueCfg);
                for (CustomerStageRelation relation : dataList) {
                    //openDelay 是为了方便OL验证的，不要喷
                    if (((System.currentTimeMillis() - relation.getCreateTime().getTime()) > followClueTime || openDelay) &&
                            employeeIdRemindRecordMap.get(relation.getEmployeeId()) == null && !sendKey.contains(relation.getStageId() + ":" +relation.getEmployeeId())) {
                        log.info("存在客户,在阶段:{}停留时间超过{}天,开始向员工:{}发送延迟消息准备首次提醒"
                                , relation.getStageId(), followClueCfg.getRuleValue(),relation.getEmployeeId());
                        //发送延迟消息
                        CustomerStageRemindEvent event = buildEvent(relation, followClueCfg);
                        dqClient.sendMsg(DqConfig.CUSTOMER_STAGE_REMIND,
                                delayTime.intValue(),
                                TimeUnit.MILLISECONDS, JSON.toJSONString(event), relation.getStageId() + relation.getCustomerId());
                        sendKey.add(relation.getStageId() + ":" +relation.getEmployeeId());
                    }
                }


                ClueCfg cycleClueCfg = clueCfgs.stream().filter(i ->
                        PotentialSettingEnum.CUSTOMER_PROCESS_CYCLE.equals(i.getPotentialSettingEnum())).findAny().orElse(null);
                if (cycleClueCfg == null || Boolean.FALSE.equals(cycleClueCfg.getRuleOpenFlag())) {
                    pageNum++;
                    continue;
                }

                long cycleClueTime = calculateClueCfgTime(cycleClueCfg);

                for (CustomerStageRelation relation : dataList) {

                    QueryListRemindRecordRequest queryListRemindRecordRequest = new QueryListRemindRecordRequest();
                    queryListRemindRecordRequest.setStageId(relation.getStageId());
                    queryListRemindRecordRequest.setEmployeeIdList(Collections.singletonList(relation.getEmployeeId()));
                    List<CustomerStageRemindRecord> remindRecords = SoaUtil.unpack(remindRecordService.queryList(queryListRemindRecordRequest)).getDataList();
                    Long time = relation.getCreateTime().getTime();
                    if(CollectionUtils.isNotEmpty(remindRecords)){
                        //获取上一次发送日期的起始时间
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(remindRecords.get(0).getLatestRecordTime());
                        calendar.set(Calendar.HOUR_OF_DAY,0);
                        calendar.set(Calendar.MINUTE,0);
                        calendar.set(Calendar.SECOND,0);
                        time = calendar.getTimeInMillis();
                    }
                    if ((System.currentTimeMillis() - time > cycleClueTime || openDelay) &&
                            employeeIdRemindRecordMap.get(relation.getEmployeeId()) != null &&
                            !sendKey.contains(relation.getStageId() + ":" +relation.getEmployeeId())) {
                        log.info("存在客户,在阶段:{}停留时间超过{}天,开始向员工:{}发送延迟消息准备周期提醒"
                                , relation.getStageId(), followClueCfg.getRuleValue(),relation.getEmployeeId());
                        //发送延迟消息
                        CustomerStageRemindEvent event = buildEvent(relation,cycleClueCfg);
                        dqClient.sendMsg(DqConfig.CUSTOMER_STAGE_REMIND,
                                delayTime.intValue(),
                                TimeUnit.MILLISECONDS, JSON.toJSONString(event), relation.getStageId() + relation.getCustomerId());
                        sendKey.add(relation.getStageId() + ":" +relation.getEmployeeId());
                    }
                }
            }catch (Exception e){
                log.error("RemindEmployeeFollowUpThread error",e);
            }
            pageNum++;
        } while (CollectionUtils.isNotEmpty(dataList) && dataList.size() == pageSize);


    }

    private long calculateDelayTime(ClueCfg clueCfg) {
        // QA 方便测试，超过一分钟没有跟进就可以发送提醒了
        if(Boolean.TRUE.equals(openDelay)) {
            return 20 * 1000L;
        }
        Long ruleEventValue = clueCfg.getRuleEventValue();
        Calendar instance = Calendar.getInstance();
        instance.set(Calendar.HOUR, Math.toIntExact(ruleEventValue));
        //补充一个随机数，避免延迟队列同一时间压力过大
        //5分钟内随机
        int i = RandomUtils.nextInt(0, 5 * 60 * 1000);
        return instance.getTimeInMillis() - System.currentTimeMillis() + i + 10 * 1000;
    }

    /**
     * 计算提醒相差间隔毫秒数
     *
     * @param clueCfg
     * @return
     */
    private long calculateClueCfgTime(ClueCfg clueCfg) {
        return Long.parseLong(clueCfg.getRuleValue()) * 24 * 60 * 60 * 1000;
       /* / QA 方便测试，超过一分钟没有跟进就可以发送提醒了
        return 60 * 1000;*/
    }

    private CustomerStageRemindEvent buildEvent(CustomerStageRelation relation, ClueCfg clueCfg){
        CustomerStageRemindEvent event = new CustomerStageRemindEvent();
        event.setCustomerId(relation.getCustomerId());
        event.setEmployeeId(relation.getEmployeeId());
        event.setSettingEnum(clueCfg.getPotentialSettingEnum());
        event.setStageId(relation.getStageId());
        event.setProcessId(relation.getProcessId());
        event.setPrivateSphereId(relation.getPrivateSphereId());
        return event;
    }


    private SingleRequest<CustomerStageRelation> buildFetchRelationListRequest(int pageNum) {
        SingleRequest<CustomerStageRelation> singleRequest = new SingleRequest<>();
        singleRequest.setPageNum(pageNum);
        singleRequest.setPageSize(pageSize);
        singleRequest.setNeedPage(true);
        CustomerStageRelation relation = new CustomerStageRelation();
        relation.setCurrentStage(true);
        relation.setCustomerStage(relation.toCustomerStage(stageId));
        relation.setPrivateSphere(privateSphere);
        relation.setHasEnd(Boolean.FALSE);
        singleRequest.setData(relation);
        singleRequest.setPrivateSphere(privateSphere);
        return singleRequest;
    }

}
